﻿using DGZImp.Core.EFDbContext;
using DGZImp.Core.Exceptions;
using DGZImp.Core.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using DGZImp.Core.DbSqlSugar;
using System.Security.Cryptography;
using DocumentFormat.OpenXml.Office2019.Excel.RichData2;

namespace ATkg.BizAppProject.Services
{
    public class AmesSyncInventoryService : IDependency
    {
        public ISqlSugarClient Db = AutofacContainerModule.GetService<ServiceDbContext>()?.SqlSugarClient;
        public IConfiguration _config;
        public HttpClient client = null;
        public static IHttpClientFactory _httpClientFactory { get; set; }

        public string url = "";
        public string db = "";
        public string userName = "";
        public string password = "";

        public string url_aike = "";
        public string db_aike = "";
        public string userName_aike = "";
        public string password_aike = "";

        public string url_beifang = "";
        public string db_beifang = "";
        public string userName_beifang = "";
        public string password_beifang = "";

        public static int? uid = 0;

        public ILogger<AmesSyncService> logger { get; set; }

        public AmesSyncInventoryService(IConfiguration configuration, IHttpClientFactory httpClientFactory)
        {
            _config = configuration;
            _httpClientFactory = httpClientFactory;
            this.url = _config["Interfaces:AnTaiMes:Url"];
            this.db = _config["Interfaces:AnTaiMes:Db"];
            this.userName = _config["Interfaces:AnTaiMes:UserName"];
            this.password = _config["Interfaces:AnTaiMes:Password"];

            this.url_aike = _config["Interfaces:AiKeMes:Url_AiKe"];
            this.db_aike = _config["Interfaces:AiKeMes:Db_AiKe"];
            this.userName_aike = _config["Interfaces:AiKeMes:UserName_AiKe"];
            this.password_aike = _config["Interfaces:AiKeMes:Password_AiKe"];

            this.url_beifang = _config["Interfaces:BfMes:Url_Bf"];
            this.db_beifang = _config["Interfaces:BfMes:Db_Bf"];
            this.userName_beifang = _config["Interfaces:BfMes:UserName_Bf"];
            this.password_beifang = _config["Interfaces:BfMes:Password_Bf"];
        }

        /// <summary>
        /// 调用AMES接口 通用方法
        /// </summary>
        public async Task<JObject> Call(string service, string method, List<dynamic> args)
        {
            client = _httpClientFactory.CreateClient();
            var json = new
            {
                jsonrpc = "2.0",
                method = "call",
                @params = new { service = service, method = method, args = args },
                id = Guid.NewGuid(),
            };
            try
            {
                Console.WriteLine(JsonConvert.SerializeObject(json));
                Console.WriteLine("准备获取uid1");
                var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
                Console.WriteLine("准备获取uid2");
                Console.WriteLine(content);
                //logger.LogInformation("---开始请求AMES获取数据---");
                //logger.LogInformation(JsonConvert.SerializeObject(json));
                client.Timeout = TimeSpan.FromSeconds(300);
                Console.WriteLine("准备获取uid3");
                Console.WriteLine(url, content);
                var response = await client.PostAsync(url, content);
                Console.WriteLine("准备获取uid4");
                response.EnsureSuccessStatusCode();
                Console.WriteLine("准备获取uid5");
                var responseString = await response.Content.ReadAsStringAsync();
                Console.WriteLine("准备获取uid6");
                //logger.LogInformation(responseString);
                var responseJson = JObject.Parse(responseString);
                Console.WriteLine("准备获取uid7");
                return responseJson;
            }
            catch (Exception e)
            {
                throw new AppException(e.Message);
            }
        }

        public async Task<JObject> Call_AiKe(string service, string method, List<dynamic> args)
        {
            client = _httpClientFactory.CreateClient();
            var json = new
            {
                jsonrpc = "2.0",
                method = "call",
                @params = new { service = service, method = method, args = args },
                id = Guid.NewGuid(),
            };
            try
            {
                Console.WriteLine(JsonConvert.SerializeObject(json));
                var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
                //logger.LogInformation("---开始请求AMES获取数据---");
                //logger.LogInformation(JsonConvert.SerializeObject(json));
                client.Timeout = TimeSpan.FromSeconds(300);
                var response = await client.PostAsync(url_aike, content);
                response.EnsureSuccessStatusCode();
                var responseString = await response.Content.ReadAsStringAsync();
                //logger.LogInformation(responseString);
                var responseJson = JObject.Parse(responseString);
                return responseJson;
            }
            catch (Exception e)
            {
                throw new AppException(e.Message);
            }
        }

        public async Task<JObject> Call_BeiFang(string service, string method, List<dynamic> args)
        {
            client = _httpClientFactory.CreateClient();
            var json = new
            {
                jsonrpc = "2.0",
                method = "call",
                @params = new { service = service, method = method, args = args },
                id = Guid.NewGuid(),
            };
            try
            {
                Console.WriteLine(JsonConvert.SerializeObject(json));
                var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
                //logger.LogInformation("---开始请求AMES获取数据---");
                //logger.LogInformation(JsonConvert.SerializeObject(json));
                client.Timeout = TimeSpan.FromSeconds(300);
                var response = await client.PostAsync(url_beifang, content);
                response.EnsureSuccessStatusCode();
                var responseString = await response.Content.ReadAsStringAsync();
                //logger.LogInformation(responseString);
                var responseJson = JObject.Parse(responseString);
                return responseJson;
            }
            catch (Exception e)
            {
                throw new AppException(e.Message);
            }
        }


        public async Task<JObject> CallSearchRead(string model, List<object> domain, List<string> fields, object pageData)
        {
            var param = new List<object>();
            param.Add(db);
            //if (uid == null || uid == 0)
                uid = await GetOdooUid(userName, password);
            param.Add(uid);
            param.Add(password);
            param.Add(model);
            param.Add("search_read");
            param.Add(new List<object> { domain, fields });
            param.Add(pageData);
            JObject data = null;
            try
            {
                data = await Call("object", "execute_kw", param);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"获取aMES数据失败，请求内容：{JsonConvert.SerializeObject(param)}，错误信息：{ex.Message}");
                throw new AppException(ex.ToString());
            }
            return data;
        }

        public async Task<JObject> CallSearchRead_AiKe(string model, List<object> domain, List<string> fields, object pageData)
        {
            var param = new List<object>();
            param.Add(db_aike);
            //if (uid == null || uid == 0)
            uid = await GetOdooUid_AiKe(userName_aike, password_aike);
            param.Add(uid);
            param.Add(password_aike);
            param.Add(model);
            param.Add("search_read");
            param.Add(new List<object> { domain, fields });
            param.Add(pageData);
            JObject data = null;
            try
            {
                data = await Call_AiKe("object", "execute_kw", param);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"获取aMES数据失败，请求内容：{JsonConvert.SerializeObject(param)}，错误信息：{ex.Message}");
                throw new AppException(ex.ToString());
            }
            return data;
        }

        public async Task<JObject> CallSearchRead_BeiFang(string model, List<object> domain, List<string> fields, object pageData)
        {
            var param = new List<object>();
            param.Add(db_beifang);
            //if (uid == null || uid == 0)
            uid = await GetOdooUid_BeiFang(userName_beifang, password_beifang);
            param.Add(uid);
            param.Add(password_beifang);
            param.Add(model);
            param.Add("search_read");
            param.Add(new List<object> { domain, fields });
            param.Add(pageData);
            JObject data = null;
            try
            {
                data = await Call_BeiFang("object", "execute_kw", param);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"获取aMES数据失败，请求内容：{JsonConvert.SerializeObject(param)}，错误信息：{ex.Message}");
                throw new AppException(ex.ToString());
            }
            return data;
        }

        public async Task<JObject> CallRead(string model, List<object> domain, List<string> fields, object pageData)
        {
            var param = new List<object>();
            param.Add(db);
            //if (uid == null || uid == 0)
                uid = await GetOdooUid(userName, password);
            param.Add(uid);
            param.Add(password);
            param.Add(model);
            param.Add("read");
            param.Add(new List<object> { domain, fields });
            // param.Add(pageData);
            JObject data = null;
            try
            {
                data = await Call("object", "execute_kw", param);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"获取aMES数据失败，请求内容：{JsonConvert.SerializeObject(param)}，错误信息：{ex.Message}");
                throw new AppException(ex.ToString());
            }
            return data;
        }

        public async Task<JObject> CallRead_AiKe(string model, List<object> domain, List<string> fields, object pageData)
        {
            var param = new List<object>();
            param.Add(db);
            //if (uid == null || uid == 0)
                uid = await GetOdooUid_AiKe(userName_aike, password_aike);
            param.Add(uid);
            param.Add(password_aike);
            param.Add(model);
            param.Add("read");
            param.Add(new List<object> { domain, fields });
            // param.Add(pageData);
            JObject data = null;
            try
            {
                data = await Call("object", "execute_kw", param);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"获取aMES数据失败，请求内容：{JsonConvert.SerializeObject(param)}，错误信息：{ex.Message}");
                throw new AppException(ex.ToString());
            }
            return data;
        }

        /// <summary>
        /// 获取odoo平台用户id
        /// </summary>
        public async Task<int?> GetOdooUid(string username, string password)
        {
            var res = await Call("common", "login", new List<dynamic> { db, username, password });
            return Convert.ToInt32(res["result"]);
        }

        public async Task<int?> GetOdooUid_AiKe(string username, string password)
        {
            var res = await Call_AiKe("common", "login", new List<dynamic> { db_aike, username, password });
            return Convert.ToInt32(res["result"]);
        }

        public async Task<int?> GetOdooUid_BeiFang(string username, string password)
        {
            var res = await Call_BeiFang("common", "login", new List<dynamic> { db_beifang, username, password });
            return Convert.ToInt32(res["result"]);
        }

        /// <summary>
        /// 获取北京空港10.7.1.3中仓库-库存查看-原料库中的所有数据
        /// </summary>
        /// 
        public async Task<List<ResultAdd>> SyncMaterialInventory_KongGang()
        {
            var qDomain = new List<object> {
                //网页开发者模式中Payload中的domain
                new List<object> { "location_id", "child_of", 1481 }
            };

            var qFields = new List<string> {
                "nc_code",
                "product_id",
                "product_uom_id",
                "qty"
            };
            var qPage = new
            {
                context = new { lang = "zh_CN", tz = "Asia/Shanghai" },
                limit = 10000,
                offset = 0,
                order = "product_id desc",
            };

            var resp = await CallSearchRead("stock.quant", qDomain, qFields, qPage);

            if (resp.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp["error"].ToString()}";
                throw new AppException(message);
            }
            var res = (JArray)resp["result"];

            if (res == null || res.Count <= 0)
            {
                return null;
            }
            var r = new List<ResultAdd>();

            for (var i = 0; i < res.Count; i++)
            {
                var x = (JObject)res[i];
                r.Add(new ResultAdd
                {
                    //nc_code = x["nc_code"].ToString(),
                    ProductId = x["product_id"] is JArray ? JArray.FromObject(x["product_id"])[1].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    //product_uom_id = x["product_uom_id"] is JArray ? JArray.FromObject(x["product_uom_id"])[1].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    Qty = (decimal)x["qty"],

                });

            }
            return r;
        }
        public class ResultAdd
        {
            public string ProductId { get; set; }
            public decimal Qty { get; set; }
        }

        public async Task<List<ResultAdd>> SyncMaterialInventory_AiKe()
        {
            var qDomain = new List<object> {
                //网页开发者模式中Payload中的domain
                new List<object> { "location_id", "child_of", 1481 }
            };

            var qFields = new List<string> {
                "nc_code",
                "product_id",
                "product_uom_id",
                "qty"
            };
            var qPage = new
            {
                context = new { lang = "zh_CN", tz = "Asia/Shanghai" },
                limit = 10000,
                offset = 0,
                order = "name desc",
            };

            var resp = await CallSearchRead_AiKe("stock.quant", qDomain, qFields, qPage);

            if (resp.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp["error"].ToString()}";
                throw new AppException(message);
            }
            var res = (JArray)resp["result"];

            if (res == null || res.Count <= 0)
            {
                return null;
            }
            var r = new List<ResultAdd>();

            for (var i = 0; i < res.Count; i++)
            {
                var x = (JObject)res[i];
                r.Add(new ResultAdd
                {
                    //nc_code = x["nc_code"].ToString(),
                    ProductId = x["product_id"] is JArray ? JArray.FromObject(x["product_id"])[1].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    //product_uom_id = x["product_uom_id"] is JArray ? JArray.FromObject(x["product_uom_id"])[1].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    Qty = (decimal)x["qty"],

                });

            }
            return r;
        }

        public async Task<List<ResultAdd>> SyncMaterialInventory_BeiFang(string location)
        {
            //List<object> qDomain = new List<object> {
            //        //网页开发者模式中Payload中的domain
                
            //        new List<object> { "location_id", "child_of", 1481 }
            //        //new List<object> { "location_id", "child_of", 27229 }
            //    };
            var qDomain = new List<object>(); // 先声明变量，但不初始化

            if (location == "beifang")
            {
                qDomain = new List<object>
                {
            new List<object> { "location_id", "child_of", 1481 }
                };
            }
            else if (location == "ningbo")
            {
                qDomain = new List<object>
                {
            new List<object> { "location_id", "child_of", 27229 }
                };
            }

            var qFields = new List<string> {
                "nc_code",
                "product_id",
                "product_uom_id",
                "quantity"
            };
            var qPage = new
            {
                context = new { lang = "zh_CN", tz = "Asia/Shanghai" },
                limit = 10000,
                offset = 0,
                order = "product_id desc",
            };

            var resp = await CallSearchRead_BeiFang("stock.quant", qDomain, qFields, qPage);

            if (resp.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp["error"].ToString()}";
                throw new AppException(message);
            }
            var res = (JArray)resp["result"];

            if (res == null || res.Count <= 0)
            {
                return null;
            }
            var r = new List<ResultAdd>();

            for (var i = 0; i < res.Count; i++)
            {
                var x = (JObject)res[i];
                r.Add(new ResultAdd
                {
                    //nc_code = x["nc_code"]?.ToString(),
                    //productId = x["product_id"] is JArray ? JArray.FromObject(x["product_id"])[display_name].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    ProductId = x["product_id"]?[1]?.ToString(),
                    //product_uom_id = x["product_uom_id"]?[1]?.ToString(),
                    //product_uom_id = x["product_uom_id"] is JArray ? JArray.FromObject(x["product_uom_id"])[0].ToString().Split(new String[] { "/" }, StringSplitOptions.None)[0] : "",
                    Qty = (decimal)x["quantity"],

                });

            }
            return r;
        }

        public async Task SyncMaterialInventory_Deal(List<ResultAdd> r1, List<ResultAdd> r2, List<ResultAdd> r3, List<ResultAdd> r4)
        {
            if (r1 is null || r2 is null || r3 is null || r4 is null)
            {
                throw new ArgumentNullException(nameof(r1));
                throw new ArgumentNullException(nameof(r2));
                throw new ArgumentNullException(nameof(r3));
                throw new ArgumentNullException(nameof(r4));
            }
            // 从Material_Zhenghe数据表中获取所有数据
            var res = await Db.Set<Material_Zhenghe>().ToListAsync();
            var r = new List<Material_Look>();
            r1.ForEach(x => {
                // 将r1中的产品代码与从Material_Zhenghe数据表中获取到的产品代码对比，返回符合的Material_Zhenghe中的数据
                var tmp = res.Where(i => i.ProductIdKg == x.ProductId).FirstOrDefault();
                //if (tmp == null) throw new AppException($"{x.ProductId}找不到对应的统称");
                r.Add(new Material_Look
                {
                    //tmp是从数据库中获取的数据
                    ProductId = tmp?.ProductId,
                    ProductIdKg = x.ProductId,
                    ProductIdSd = tmp?.ProductIdSd,
                    ProductIdBf = tmp?.ProductIdBf,
                    ProductIdNb = tmp?.ProductIdBf,
                    QtyKg = x.Qty,
                    Qty = x.Qty
                });
            });

            r2.ForEach(x => {
                var tmp = res.Where(i => i.ProductIdSd == x.ProductId).FirstOrDefault();
                //if (tmp == null) throw new AppException($"{x.ProductId}找不到对应的统称");
                r.Add(new Material_Look
                {
                    ProductId = tmp?.ProductId,
                    ProductIdSd = x.ProductId,
                    ProductIdKg = tmp?.ProductIdKg,
                    ProductIdBf = tmp?.ProductIdBf,
                    ProductIdNb = tmp?.ProductIdBf,
                    QtySd = x.Qty,
                    Qty = x.Qty
                });
            });

            r3.ForEach(x => {
                var tmp = res.Where(i => i.ProductIdBf == x.ProductId).FirstOrDefault();
                //if (tmp == null) throw new AppException($"{x.ProductId}找不到对应的统称");
                r.Add(new Material_Look
                {
                    ProductId = tmp?.ProductId,
                    ProductIdBf = x.ProductId,
                    ProductIdSd = tmp?.ProductIdSd,
                    ProductIdKg = tmp?.ProductIdKg,
                    ProductIdNb = tmp?.ProductIdBf,
                    QtyBf = x.Qty,
                    Qty = x.Qty
                });
            });
            r4.ForEach(x =>
            {
                var tmp = res.Where(i => i.ProductIdBf == x.ProductId).FirstOrDefault();
                //if (tmp == null) throw new AppException($"{x.ProductId}找不到对应的统称");
                r.Add(new Material_Look
                {
                    ProductId = tmp?.ProductId,
                    ProductIdNb = x.ProductId,
                    ProductIdSd = tmp?.ProductIdSd,
                    ProductIdKg = tmp?.ProductIdKg,
                    ProductIdBf = tmp?.ProductIdBf,
                    QtyNb = x.Qty,
                    Qty = x.Qty
                });
            });
            //将数据进行整合，重复的数量进行累加，合并成一条
            var data = r.GroupBy(x => x.ProductId).Select(x => new Material_Look
            {
                ProductId = x.Key,
                Qty = x.Sum(x => x.Qty),
                ProductIdKg = x.Min(x => x.ProductIdKg),
                ProductIdSd = x.Min(x => x.ProductIdSd),
                ProductIdBf = x.Min(x => x.ProductIdBf),
                ProductIdNb = x.Min(x => x.ProductIdNb),
                QtyKg = x.Sum(x => x.QtyKg),
                QtySd = x.Sum(x => x.QtySd),
                QtyBf = x.Sum(x => x.QtyBf),
                QtyNb = x.Sum(x => x.QtyNb),

            }).ToList();

            await Db.DoDeleteAsync<Material_Look>(x=>x.IsValid > 0);
            await Db.DoInsertAsync<Material_Look>(data);
        }
    }
}
